﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;

namespace Love.Awesome.SimpleTiledImplementation
{
    ///https://github.com/karai17/Simple-Tiled-Implementation/blob/master/sti/utils.lua
    internal static class Utils
    {
        ///<summary>格式化路径字符串。</summary>
        public static string FormatPath(string path)
        {
            return path;
        }

        ///<summary>Compensation for scale/rotation shift. 刻度/旋转偏移补偿。</summary>
        public static Love.Vector2 Compensate(Tile tile, float tileX, float tileY, float tileW, float tileH)
        {
            var compx = 0f;
            var compy = 0f;

            if (tile.SX < 0) compx = tileW;
            if (tile.SY < 0) compy = tileH;

            if (tile.R > 0)
            {
                tileX = tileX + tileH - compy;
                tileY = tileY + tileH + compx - tileW;
            }
            else if (tile.R < 0)
            {
                tileX = tileX + compy;
                tileY = tileY - compx + tileH;
            }
            else
            {
                tileX = tileX + compx;
                tileY = tileY + compy;
            }

            return new Vector2() { X = tileX, Y = tileY };
        }


        public static void CacheImage(string path, Image image)
        {
            if (image == null) return;
            image.SetFilter(FilterMode.Nearest, FilterMode.Nearest);
            if (STI.Cache.ContainsKey(path) == false)
            {
                STI.Cache.Add(path, image);
            }

        }

        public static int GetTiles(float imageW, float tileW, float margin, float spacing)
        {
            imageW = imageW - margin;
            var n = 0;

            while (imageW >= tileW)
            {
                imageW = imageW - tileW;
                if (n != 0) imageW = imageW - spacing;
                if (imageW > 0) n = n + 1;
            }

            return n;
        }

        public static int[] GetDecompressedData(IntPtr dataPointer)
        {
            throw new NotImplementedException();
        }

        public static int[] GetDecompressedData(byte[] data)
        {
            var arr = new int[data.Length];
            for (int i = 0; i < data.Length; i++)
            {
                arr[i] = ByteToInt(data[i]);
            }
            return arr;
        }

        private static int ByteToInt(byte b)
        {
            if (b <= '9' || b >= '0') return b - '0';
            return 0;
        }

        public static IList<Vector2> ConvertEllipseToPolygon(float x, float y, float w, float h, int max_segments)
        {
            var segments = CalcSegments(max_segments, x, y, w, h);
            var vertices = new List<Vector2>();
            vertices.Add(new Vector2(x + w / 2, y + h / 2));

            for (int i = 0; i <= segments; i++)
            {
                var angle = (1f * i / segments) * Mathf.PI * 2;
                var px = x + w / 2 + Mathf.Cos(angle) * w / 2;
                var py = y + h / 2 + Mathf.Sin(angle) * h / 2;
                vertices.Add(new Vector2(px, py));
            }
            return vertices;
        }

        public static int CalcSegments(int segments, float x, float y, float w, float h)
        {
            var vertices = new List<Vector2>();
            var v = new float[] { 1, 2, Love.Mathf.Ceil(segments / 4 - 1), Mathf.Ceil(segments / 4) };
            var m = Physics.GetMeter(); // default 32

            foreach (var i in v)
            {
                var angle = (i / segments) * Mathf.PI * 2;
                var px = x + w / 2 + Mathf.Cos(angle) * w / 2;
                var py = y + h / 2 + Mathf.Sin(angle) * h / 2;
                vertices.Add(new Vector2(px / m, py / m));
            }

            var dist1 = Vector2.Distance(vertices[0], vertices[2]);
            var dist2 = Vector2.Distance(vertices[1], vertices[3]);

            if (dist1 < 0.0025 || dist2 < 0.0025)
            {
                return CalcSegments(segments - 2, x, y, w, h);
            }

            return segments;

        }

        public static Vector2 RotateVertex(Map map, Vector2 vertex, float x, float y, float cos, float sin, float oy = 0)
        {
            if (map.Orientation == Orientation.Isometric)
            {
                var v = ConvertIsometricToScreen(map, x, y);
                x = v.X;
                y = v.Y;
                var v2 = ConvertIsometricToScreen(map, vertex.X, vertex.Y);
                vertex.X = v2.X;
                vertex.Y = v2.Y;
            }

            vertex.X = vertex.X - x;
            vertex.Y = vertex.Y - y;

            return new Vector2(
                x + cos * vertex.X - sin * vertex.Y,
                y + sin * vertex.X + cos * vertex.Y - oy);
        }

        public static Vector2 ConvertIsometricToScreen(Map map, float x, float y)
        {
            var mapW = map.Width;
            var tileW = map.TileWidth;
            var tileH = map.TileHeight;
            var tileX = x / tileH;
            var tileY = y / tileH;
            var offsetX = mapW * tileW / 2;

            return new Vector2((tileX - tileY) * tileW / 2 + offsetX, (tileX + tileY) * tileH / 2);
        }

        public static Color HexToColor(string hex)
        {
            var redHex = hex[0].ToString() + hex[1];
            var greenHex = hex[2].ToString() + hex[3];
            var blueHex = hex[4].ToString() + hex[5];
            var r = GetRGBPerHex(redHex) / 255f;
            var g = GetRGBPerHex(greenHex) / 255f;
            var b = GetRGBPerHex(blueHex) / 255f;

            var newColor = new Color(r, g, b, 1);
            return newColor;
        }
        private static int GetRGBPerHex(string code)
        {
            var result = 0;
            switch (code[0])
            {
                case '1':
                    result += 16;
                    break;
                case '2':
                    result += 32;
                    break;
                case '3':
                    result += 48;
                    break;
                case '4':
                    result += 64;
                    break;
                case '5':
                    result += 80;
                    break;
                case '6':
                    result += 96;
                    break;
                case '7':
                    result += 112;
                    break;
                case '8':
                    result += 128;
                    break;
                case '9':
                    result += 144;
                    break;
                case 'A':
                    result += 160;
                    break;
                case 'B':
                    result += 176;
                    break;
                case 'C':
                    result += 192;
                    break;
                case 'D':
                    result += 208;
                    break;
                case 'E':
                    result += 224;
                    break;
                case 'F':
                    result += 240;
                    break;
            }
            switch (code[0])
            {
                case '1':
                    result += 1;
                    break;
                case '2':
                    result += 2;
                    break;
                case '3':
                    result += 3;
                    break;
                case '4':
                    result += 4;
                    break;
                case '5':
                    result += 5;
                    break;
                case '6':
                    result += 6;
                    break;
                case '7':
                    result += 7;
                    break;
                case '8':
                    result += 8;
                    break;
                case '9':
                    result += 9;
                    break;
                case 'A':
                    result += 10;
                    break;
                case 'B':
                    result += 11;
                    break;
                case 'C':
                    result += 12;
                    break;
                case 'D':
                    result += 13;
                    break;
                case 'E':
                    result += 14;
                    break;
                case 'F':
                    result += 15;
                    break;
            }

            return result;
        }

        private static Color PixelFunction(int x, int y, Color color1, Color color2)
        {
            if (color1.r == color2.r && color1.g == color2.g && color1.b == color2.b)
            {
                return new Color(color1.r, color1.g, color1.b, 0);
            }
            return color1;
        }

        public static void FixTransparentColor(TileSet tileSet, string path)
        {
            var imageData = Love.Image.NewImageData(path);
            tileSet.Image = Love.Graphics.NewImage(imageData);

            if (string.IsNullOrWhiteSpace(tileSet.TransparentColor) == false)
            {
                var tc = HexToColor(tileSet.TransparentColor);
                imageData.MapPixel((x, y, color) => PixelFunction(x, y, color, tc));
            }

            //if(tileSet.)
        }

    }
}
